/**
 * 
 */
package com.zufangbao.earth.web.controller.assets;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.demo2do.core.entity.Result;
import com.demo2do.core.persistence.support.Filter;
import com.demo2do.core.utils.DateUtils;
import com.demo2do.core.utils.JsonUtils;
import com.demo2do.core.web.interceptor.MenuSetting;
import com.demo2do.core.web.resolver.Page;
import com.zufangbao.sun.entity.company.Company;
import com.zufangbao.sun.entity.company.corp.App;
import com.zufangbao.sun.entity.contract.Contract;
import com.zufangbao.sun.entity.contract.ContractStatus;
import com.zufangbao.sun.entity.contract.PaymentInstrument;
import com.zufangbao.sun.entity.customer.Customer;
import com.zufangbao.sun.entity.factoring.AssetPackage;
import com.zufangbao.sun.entity.factoring.FactoringContract;
import com.zufangbao.sun.entity.house.House;
import com.zufangbao.sun.entity.house.HouseType;
import com.zufangbao.sun.entity.icbc.business.BankcardType;
import com.zufangbao.sun.entity.icbc.business.ContractAccount;
import com.zufangbao.sun.entity.order.Order;
import com.zufangbao.sun.entity.order.OrderStatus;
import com.zufangbao.sun.entity.order.RepaymentType;
import com.zufangbao.sun.service.AppService;
import com.zufangbao.sun.service.AssetPackageService;
import com.zufangbao.sun.service.CompanyService;
import com.zufangbao.sun.service.ContractAccountService;
import com.zufangbao.sun.service.ContractService;
import com.zufangbao.sun.service.CustomerService;
import com.zufangbao.sun.service.FactoringContractService;
import com.zufangbao.sun.service.HouseService;
import com.zufangbao.sun.service.OrderService;

/**
 * 资产包管理
 * @author wk
 *
 */
@RestController
@RequestMapping("/assets-package")
@MenuSetting("menu-data")
public class AssetsPackageController {

	private static final String YYYY_MM_DD = "yyyy-MM-dd";
	@Autowired
	private AssetPackageService assetPackageService;
	@Autowired
	private AppService appService;
	@Autowired
	private CompanyService companyService;
	@Autowired
	private ContractService contractService;
	@Autowired
	private ContractAccountService contractAccountService;
	@Autowired
	private FactoringContractService factoringContractService;
	@Autowired
	private CustomerService customerService;
	@Autowired
	private HouseService houseService;
	@Autowired
	private OrderService orderService;
	
	@RequestMapping("")
	@MenuSetting("submenu-assets-package")
	public ModelAndView list(@RequestParam(value = "contractNo" , required = false)String contractNo, Page page, HttpServletRequest request){
		
		Filter filter = new Filter();
		filter.addLike("contract.contractNo", contractNo);
		
		List<AssetPackage> assetsPackageList = new ArrayList<AssetPackage>();
		
		if(StringUtils.isEmpty(contractNo)){
			
			assetsPackageList = assetPackageService.list(AssetPackage.class,page);
		}else{
			
			assetsPackageList = assetPackageService.list(AssetPackage.class,filter,page);
		}
		
		ModelAndView modelAndView = new ModelAndView("assets/assets-list");
		modelAndView.addObject("assetsPackageList", assetsPackageList);
		modelAndView.addObject("contractNo", contractNo);
		modelAndView.addObject("page", page);
		
		String queryString = request.getQueryString();
		
		if(StringUtils.isEmpty(queryString)){
			
			return modelAndView;
		}
		Map<String, String> queries = com.demo2do.core.utils.StringUtils.parseQueryString(queryString);
		queries.remove("page");
		modelAndView.addObject("queryString", com.demo2do.core.utils.StringUtils.toQueryString(queries));
		
		return modelAndView;
	}
	
	@RequestMapping("searcch")
	@MenuSetting("submenu-assets-package")
	public ModelAndView search(Page page){
		
		ModelAndView modelAndView = new ModelAndView("assets/assets-search");
		
		return modelAndView;
		
	}
	
	@RequestMapping(value="excel-create-assetData",method=RequestMethod.POST)
	public @ResponseBody String importAssetPackageExcel(MultipartFile file,String app_id){
		try {
			InputStream inputStream = file.getInputStream();
			assetPackageService.importAssetPackagesViaExcel(inputStream);
			return "导入成功";
		} catch (Exception e) {
			e.printStackTrace();
			return "导入失败";
		}
	}
	
	@RequestMapping("create")
	@MenuSetting("submenu-assets-package")
	public ModelAndView create(){
		
		ModelAndView modelAndView = new ModelAndView("assets/asset-create");
		
		List<Company> companyList = companyService.loadAll(Company.class);
		List<App> appList = appService.loadAll(App.class);
		List<FactoringContract> factoringContractList = factoringContractService.loadAll(FactoringContract.class);
		modelAndView.addObject("companyList", companyList);
		modelAndView.addObject("appList", appList);
		modelAndView.addObject("factoringContractList", factoringContractList);
		modelAndView.addObject("RepaymentType", RepaymentType.values());
		modelAndView.addObject("isFactoring", true);
		
		return modelAndView;
	}
	
	@RequestMapping(value = "add", method = RequestMethod.POST )
	public @ResponseBody String add(@RequestParam(value = "company", required = false)String factoringCompanyId,
														 @RequestParam(value = "factoringContractNo", required = false)String factoringContractNo,
														 @RequestParam(value = "otsdAmt", required = false)String otsdAmt,
														 @RequestParam(value = "latestSettleDate", required = false)String latestSettleDate,
														 @RequestParam(value = "app", required = false)String appId,
														 @RequestParam("contractNo")String contractNo,
														 @RequestParam("customerName")String customerName,
														 @RequestParam(value = "payerName")String payerName,
														 @RequestParam(value = "payAcNo")String payAcNo,
														 @RequestParam("start")String rentStartDate,
														 @RequestParam("end")String rentEndDate,
														 @RequestParam("monthFee")String monthFee,
														 @RequestParam("deposit")String deposit,
														 @RequestParam("houseNo")String houseNo,
														 @RequestParam("address")String address,
														 @RequestParam(value="phone" ,required=	false)String phone,
														 @RequestParam("rentOrderNoFixed")String rentOrderNoFixed,
														 @RequestParam("rentOrderNoChanged")String rentOrderNoChanged,
														 @RequestParam("rentOrderFirstPayDate")String rentOrderFirstPayDate,
														 @RequestParam("rentOrderFirstPayAmt")String rentOrderFirstPayAmt,
														 @RequestParam("rentOrderTerm")String rentOrderTerm,
														 @RequestParam("orderNo")String[] orderNo,
														 @RequestParam("orderAmount")String[] orderAmount,
														 @RequestParam("orderPayDate")String[] orderPayDate,
														 @RequestParam("startDate")String[] startDate,
														 @RequestParam("endDate")String[] endDate,
														 @RequestParam(value = "repaymentType", required = false)Integer[] repaymentType
			){
		
		Result result = new Result();
		try{
				App app = getApp(factoringCompanyId, factoringContractNo, appId);
				Contract contract = create_contract_and_orders(contractNo,
						customerName, payerName, phone, payAcNo, rentStartDate,
						rentEndDate, monthFee, deposit, houseNo, address,
						orderNo, orderAmount, orderPayDate, repaymentType, app, startDate, endDate);
				
				if(factoringCompanyId != null){
					FactoringContract	factoringContract = factoringContractService.getFactoringContract(Long.parseLong(factoringContractNo));
					create_asset_package(otsdAmt, latestSettleDate,
							orderAmount, factoringContract, contract);
				}
				
				setMessage(result, getMsg(factoringCompanyId));
				
				return JsonUtils.toJsonString(result);
		}catch(Exception e){
				e.printStackTrace();
				result.fail().message("系统错误，请稍后再试！");
				return JsonUtils.toJsonString(result);
		}
	}

	private App getApp(String factoringCompanyId, String factoringContractNo,
			String appId) {
		App app = null;
		if(factoringCompanyId != null){
			FactoringContract	factoringContract = factoringContractService.getFactoringContract(Long.parseLong(factoringContractNo));
			app = factoringContract.getApp();
		}else{
			app = appService.load(App.class, Long.parseLong(appId));
		}
		return app;
	}

	private String getMsg(String factoringCompanyId) {
		if(factoringCompanyId == null){
			return "新增租约成功！";
		}
			return "新增资产包成功！";
	}

	private void create_asset_package(String otsdAmt, String latestSettleDate,
			String[] orderAmount, FactoringContract factoringContract,
			Contract contract) {
		AssetPackage assetPackage = createAssetsPackage(otsdAmt.trim(),
				latestSettleDate, factoringContract, contract, orderAmount);
		
		updateFactoringContract(factoringContract,assetPackage);
		
		
		assetPackageService.save(assetPackage);
	}

	private Contract create_contract_and_orders(String contractNo,
			String customerName, String payerName,String phone, String payAcNo,
			String rentStartDate, String rentEndDate, String monthFee,
			String deposit, String houseNo, String address, String[] orderNo,
			String[] orderAmount, String[] orderPayDate,
			Integer[] repaymentType, App app, String[] startDate, String[] endDate) {
		Customer customer = createCustomer(customerName.trim(),phone, app);
		
		House house = createHouse(houseNo.trim(), address.trim(), app);
		
		Contract contract = createContract(contractNo.trim(), rentStartDate,
				rentEndDate, monthFee.trim(), deposit.trim(), app, customer, house);
		
		
		customerService.save(customer);
		houseService.save(house);
		contractService.save(contract);
		
		if(StringUtils.isNotEmpty(payerName.trim()) || StringUtils.isNotEmpty(payAcNo.trim()) ){
			ContractAccount contractAccount = createContractAccount(payerName.trim(),
					payAcNo.trim(), contract);
			
			contractAccountService.save(contractAccount);
		}
		
		List<Order> orderList = createOrderList(customer, contract, orderNo, orderAmount, orderPayDate, repaymentType, startDate, endDate);

		for(Order item : orderList){
			orderService.saveOrder(item);
		}
		return contract;
	}

	private void setMessage(Result result, String message) {
		result.success().message(message);
	}

	/**
	 * @param customer
	 * @param contract
	 * @param startDate TODO
	 * @param endDate TODO
	 * @param rentOrderNoFixed
	 * @param rentOrderNoChanged
	 * @param rentOrderFirstPayDate
	 * @param rentOrderFirstPayAmt
	 * @param rentOrderTerm
	 * @return
	 */
	private List<Order> createOrderList(Customer customer, Contract contract, String[] orderNos, String[] orderAmounts, String[] orderPayDates, Integer repaymentType[], String[] startDate, String[] endDate) {
		List<Order> orderList = new ArrayList<Order>();
			for(int i = 0; i < orderNos.length; i ++){

				Order order = createOrder(customer, contract, orderNos[i].trim(), orderAmounts[i].trim(),
						orderPayDates[i].trim(), getRepayMentType(repaymentType, i), startDate[i].trim(), endDate[i].trim());
				orderList.add(order);
			}

		return orderList;
	}

	private Integer getRepayMentType(Integer[] repaymentType, int i) {
		Integer repaymentType_v =null;
		if(repaymentType != null) 
		    repaymentType_v =repaymentType[i];
		return repaymentType_v;
	}

	private Order createOrder(Customer customer, Contract contract,
			String orderNo, String rent, String orderPayDate, Integer repaymentType, String startDate, String endDate) {
		Order order = new Order();
		order.setContract(contract);
		order.setCustomer(customer);
		order.setOrderNo(orderNo);
		order.setOrderStatus(OrderStatus.UNPAID);
		order.setPaidRent(BigDecimal.ZERO);
		order.setTotalRent(new BigDecimal(rent));
		order.setStartDate(DateUtils.parseDate(startDate, YYYY_MM_DD));
		order.setEndDate(DateUtils.parseDate(endDate, YYYY_MM_DD));
		order.setDueDate(DateUtils.parseDate(orderPayDate, YYYY_MM_DD));
		if(repaymentType == null){
			order.setRepaymentType(null);
		}else{
			order.setRepaymentType(RepaymentType.fromValue(repaymentType));
		}
		return order;
	}

	/**
	 * @param otsdAmt
	 * @param latestSettleDate
	 * @param factoringContract
	 * @param contract
	 * @return
	 */
	private AssetPackage createAssetsPackage(String otsdAmt,
			String latestSettleDate, FactoringContract factoringContract,
			Contract contract, String[] orderAmount) {
		AssetPackage assetPackage = new AssetPackage();
		assetPackage.setAvailable(false);
		assetPackage.setOtsdAmt(new BigDecimal(otsdAmt));
		assetPackage.setOtsdAmtAval(new BigDecimal(otsdAmt));
		assetPackage.setAdvaStartDate(DateUtils.parseDate(latestSettleDate, YYYY_MM_DD));
		assetPackage.setLatestSettleDate(assetPackage.getAdvaStartDate());
		assetPackage.setCreateTime(new Date(System.currentTimeMillis()));
		assetPackage.setContract(contract);
		assetPackage.setFactoringContract(factoringContract);
		BigDecimal total_amt = cal_total_amt(orderAmount);
		assetPackage.setRecTransfeeTotalAmt(total_amt);
		return assetPackage;
	}

	private BigDecimal cal_total_amt(String[] orderAmount) {
		BigDecimal total_amt = new BigDecimal("0");
		for (String amount : orderAmount){
			total_amt = total_amt.add(new BigDecimal(amount.trim()));
		}
		return total_amt;
	}

	/**
	 * @param payAcNo
	 * @param contract
	 * @return
	 */
	private ContractAccount createContractAccount(String payerName, String payAcNo,
			Contract contract) {
		ContractAccount contractAccount = new ContractAccount();
		if(payAcNo.contains("*")){
			contractAccount.setBankcardType(BankcardType.CreditCard);
		}else{
			contractAccount.setBankcardType(BankcardType.DebitCard);
		}
		contractAccount.setContract(contract);
		contractAccount.setPayerName(payerName);
		contractAccount.setPayAcNo(payAcNo);
		return contractAccount;
	}

	/**
	 * @param contractNo
	 * @param rentStartDate
	 * @param rentEndDate
	 * @param monthFee
	 * @param deposit
	 * @param app
	 * @param customer
	 * @param house
	 * @return
	 */
	private Contract createContract(String contractNo, String rentStartDate,
			String rentEndDate, String monthFee, String deposit, App app,
			Customer customer, House house) {
		Contract contract = new Contract();
		contract.initialize(app, customer, house, PaymentInstrument.MONTH, rentStartDate, rentEndDate);
		contract.setContractNo(contractNo);
		contract.setMonthFee(new BigDecimal(monthFee));
		contract.setDeposit(new BigDecimal(deposit));
		contract.setContractStatus(ContractStatus.Processing);
		return contract;
	}

	/**
	 * @param houseNo
	 * @param address
	 * @param app
	 * @return
	 */
	private House createHouse(String houseNo, String address, App app) {
		House house = new House();
		house.initial(app, HouseType.BOUTIQUE);
		house.setCommunity(houseNo);
		house.setAddress(address);
		return house;
	}

	/**
	 * @param customerName
	 * @param app
	 * @param appAccount
	 * @return
	 */
	private Customer createCustomer(String customerName,String phone, App app) {
		Customer customer = new Customer();
		customer.initial(app);
		customer.setName(customerName);
		customer.setMobile(phone);
		return customer;
	}
	
	public void updateFactoringContract(FactoringContract factoringContract, AssetPackage assetPackage){
		
		factoringContract.setOtsdAmt(factoringContract.getOtsdAmt().add(assetPackage.getOtsdAmt()));
		factoringContract.setOtsdAmtAval(factoringContract.getOtsdAmtAval().add(assetPackage.getOtsdAmt()));
		factoringContract.setArAmt(factoringContract.getArAmt().add(assetPackage.getRecTransfeeTotalAmt()));
		factoringContract.setArLdgamt(factoringContract.getArLdgamt().add(assetPackage.getRecTransfeeTotalAmt()));
		
		factoringContractService.update(factoringContract);
	}
	
}